all repos — caroster @ d0d47704e427face6c4cea5a2e1326c3679f6f5d

[Octree] Group carpool to your event https://caroster.io

frontend/pages/e/[uuid]/index.tsx (view raw)

  1import {useState, useReducer, useEffect} from 'react';
  2import Box from '@material-ui/core/Box';
  3import {makeStyles, useTheme} from '@material-ui/core/styles';
  4import {useTranslation} from 'react-i18next';
  5import {initializeApollo} from '../../../lib/apolloClient';
  6import useToastStore from '../../../stores/useToastStore';
  7import useEventStore from '../../../stores/useEventStore';
  8import Layout from '../../../layouts/Default';
  9import AddToMyEventDialog from '../../../containers/AddToMyEventDialog';
 10import TravelColumns from '../../../containers/TravelColumns';
 11import NewTravelDialog from '../../../containers/NewTravelDialog';
 12import VehicleChoiceDialog from '../../../containers/VehicleChoiceDialog';
 13import WelcomeDialog from '../../../containers/WelcomeDialog';
 14import EventBar from '../../../containers/EventBar';
 15import Loading from '../../../containers/Loading';
 16import OnBoardingTour from '../../../containers/OnBoardingTour';
 17import {
 18  useUpdateEventMutation,
 19  Event as EventType,
 20  useEventByUuidQuery,
 21  EventByUuidDocument,
 22  EditEventInput,
 23  useFindUserVehiclesQuery,
 24} from '../../../generated/graphql';
 25import ErrorPage from '../../_error';
 26import useProfile from '../../../hooks/useProfile';
 27import Fab from '../../../containers/Fab';
 28import useMediaQuery from '@material-ui/core/useMediaQuery';
 29import useBannerStore from '../../../stores/useBannerStore';
 30import DrawerMenu from '../../../containers/DrawerMenu';
 31
 32const POLL_INTERVAL = 10000;
 33
 34interface Props {
 35  event: EventType;
 36  eventUUID: string;
 37}
 38
 39const EventPage = props => {
 40  const {t} = useTranslation();
 41  const {event} = props;
 42  if (!event) return <ErrorPage statusCode={404} title={t`event.not_found`} />;
 43  return <Event {...props} />;
 44};
 45
 46const Event = (props: Props) => {
 47  const {eventUUID} = props;
 48  const bannerOffset = useBannerStore(s => s.offset);
 49  const classes = useStyles({bannerOffset});
 50  const theme = useTheme();
 51  const {t} = useTranslation();
 52  const {user} = useProfile();
 53  const {data: {me: {profile: {vehicles = []} = {}} = {}} = {}, loading} =
 54    useFindUserVehiclesQuery();
 55  const addToast = useToastStore(s => s.addToast);
 56  const setEvent = useEventStore(s => s.setEvent);
 57  const eventUpdate = useEventStore(s => s.event);
 58  const setIsEditing = useEventStore(s => s.setIsEditing);
 59  const [updateEvent] = useUpdateEventMutation();
 60  const [isAddToMyEvent, setIsAddToMyEvent] = useState(false);
 61  const [openNewTravelContext, toggleNewTravel] = useState({opened: false});
 62  const [openVehicleChoice, toggleVehicleChoice] = useReducer(i => !i, false);
 63  const {data: {eventByUUID: event} = {}} = useEventByUuidQuery({
 64    pollInterval: POLL_INTERVAL,
 65    variables: {uuid: eventUUID},
 66  });
 67  const matches = useMediaQuery(theme.breakpoints.down('sm'));
 68
 69  const onSave = async e => {
 70    try {
 71      const {uuid, ...data} = eventUpdate;
 72      const {id, __typename, travels, users, waitingList, ...input} = data;
 73      await updateEvent({
 74        variables: {uuid, eventUpdate: input as EditEventInput},
 75        refetchQueries: ['eventByUUID'],
 76      });
 77      setIsEditing(false);
 78    } catch (error) {
 79      console.error(error);
 80      addToast(t('event.errors.cant_update'));
 81    }
 82  };
 83
 84  useEffect(() => {
 85    if (event) setEvent(event as EventType);
 86  }, [event]);
 87
 88  const addTravelClickHandler =
 89    user && vehicles?.length != 0
 90      ? toggleVehicleChoice
 91      : () => toggleNewTravel({opened: true});
 92
 93  if (!event || loading) return <Loading />;
 94
 95  return (
 96    <Layout
 97      className={classes.layout}
 98      pageTitle={t('event.title', {title: event.name})}
 99      menuTitle={t('event.title', {title: event.name})}
100      displayMenu={false}
101    >
102      <EventBar event={event} onAdd={setIsAddToMyEvent} onSave={onSave} />
103      <DrawerMenu />
104      <TravelColumns toggle={addTravelClickHandler} />
105      <Fab
106        onClick={addTravelClickHandler}
107        aria-label="add-car"
108        color="primary"
109        className={classes.bottomRight}
110      >
111        {t('travel.creation.title')}
112      </Fab>
113      <NewTravelDialog
114        context={openNewTravelContext}
115        toggle={() => toggleNewTravel({opened: false})}
116      />
117      <VehicleChoiceDialog
118        open={openVehicleChoice}
119        toggle={toggleVehicleChoice}
120        toggleNewTravel={toggleNewTravel}
121        vehicles={vehicles}
122      />
123      <AddToMyEventDialog
124        event={event}
125        open={isAddToMyEvent}
126        onClose={() => setIsAddToMyEvent(false)}
127      />
128      <WelcomeDialog />
129      <OnBoardingTour />
130    </Layout>
131  );
132};
133
134export async function getServerSideProps(ctx) {
135  const {uuid} = ctx.query;
136  const apolloClient = initializeApollo();
137  const {data = {}} = await apolloClient.query({
138    query: EventByUuidDocument,
139    variables: {uuid},
140  });
141  const {eventByUUID: event} = data;
142  const {host = ''} = ctx.req.headers;
143
144  return {
145    props: {
146      event,
147      eventUUID: uuid,
148      metas: {
149        title: event?.name || '',
150        url: `https://${host}${ctx.resolvedUrl}`,
151      },
152    },
153  };
154}
155
156const useStyles = makeStyles(theme => ({
157  layout: ({bannerOffset}) => ({
158    paddingTop: theme.mixins.toolbar.minHeight + bannerOffset,
159  }),
160  bottomRight: {
161    bottom: 0,
162    right: theme.spacing(6),
163
164    [theme.breakpoints.down('sm')]: {
165      right: theme.spacing(1),
166      bottom: 56,
167    },
168  },
169}));
170
171export default EventPage;